/*
 * Any.java
 *
 * Created on 20 marzo 2004, 10.38
 */

package net.ermannofranco.xml.schema;

import net.ermannofranco.xml.Static;
import net.ermannofranco.xml.SyntaxException;

/**
 * tag Any. Metodi factory in Sequence, Choice
 * 
 * @author ermanno (ermanno.franco@gmail.com)
 */
public class Any extends SchemaTag {

	private static final long serialVersionUID = 5455845544224566792L;

	// /** Costante per processare il contenuto */
	// public static final int SKIP = 2;
	// /** Costante per processare il contenuto */
	// public static final int LAX = 1;
	// /** Costante per processare il contenuto */
	// public static final int STRICT = 0;
	/** Costante per maxOccurs */
	// public static final int UNBOUNDED = 0;

	/**
	 * Creates a new instance of Any Protetto
	 * 
	 * @param level
	 *            livello di indentazione
	 * @param container
	 *            tag contenitore
	 */
	protected Any(int level, ISchemaTag container) {
		super("any", level, container);
	}

	/**
	 * imposta il tag namespace
	 * 
	 * @param ns
	 *            namespace
	 * @return autoref
	 */
	public Any setNamespace(String... ns) {
		if (ns == null || ns.length == 0)
			throw new SchemaException("namespace too minimal...");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < ns.length; i++) {
			sb.append(ns[i]).append(Static.SPACE);
		}
		sb.setLength(sb.length() - 1);
		addAttr("namespace", sb.toString());// qui e' cdata, senza convalida
		return this;
	}

	/**
	 * indica come processare il contenuto
	 * 
	 * @param anyNumber
	 *            costante
	 * @return autoref
	 */
	public Any processContents(Process anyNumber) {
		String processType = null;
		switch (anyNumber) {
		case SKIP:
			processType = "skip";
			break;
		case LAX:
			processType = "lax";
			break;
		case STRICT:
			processType = "strict";
			break;
		default:
			throw new SchemaException("Scegliere una costante di Process, "
					+ getClass().getName() + ":(" + getName() + ")");
		}
		addAttr("processContents", processType);
		return this;
	}

	/**
	 * imposta il numero minimo di occorrenze
	 * 
	 * @param minOccurs
	 *            numero di occorrenze
	 * @return autoref
	 */
	public Any setMinOccurs(int minOccurs) {
		if (minOccurs < 0)
			throw new SyntaxException(minOccurs + " non valido in minOccurs: "
					+ getName());
		addAttr("minOccurs", "" + minOccurs);// al 1 livello non e' ammesso
		return this;
	}

	/**
	 * imposta il numero massimo di occorrenze
	 * 
	 * @param maxOccurs
	 *            numero max di occorrenze
	 * @return autoref
	 */
	public Any setMaxOccurs(int maxOccurs) {
		if (maxOccurs < 0)
			throw new SyntaxException(maxOccurs + " non valido in maxOccurs: "
					+ getName());
		if (maxOccurs == Integer.MAX_VALUE) {
			addAttr("maxOccurs", "unbounded");
		} else {
			addAttr("maxOccurs", "" + maxOccurs);
		}
		return this;
	}

	/**
	 * Allow zero or unbounded occurs. Shortcut for
	 * setMinOccurs(0).setUnboundedMaxOccurs().
	 * 
	 * @return this.
	 */
	public Any setAllPossibleOccurs() {
		return setMinOccurs(0).setUnboundedMaxOccurs();
	}

	/**
	 * Shortcut for setMinOccurs(0).setMaxOccurs(1). Remember: if maxOccurs is
	 * not specified in element, default is 1 anyway.
	 * 
	 * @return this.
	 */
	public Any setZeroOrOneOccurs() {
		return setMinOccurs(0).setMaxOccurs(1);
	}

	/**
	 * Shortcut for setMinOccurs(0).
	 * 
	 * @return this.
	 */
	public Any setZeroMinOccurs() {
		return setMinOccurs(0);
	}

	/**
	 * add maxOccurs="unbounded"
	 * 
	 * @return
	 */
	public Any setUnboundedMaxOccurs() {
		return setMaxOccurs(Integer.MAX_VALUE);
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            testo della documentazione
	 * @return autoref
	 */
	public Any addDocumentation(String explanation) {
		addAnnotation().addDocumentation(explanation);
		return this;
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            testo della documentazione
	 * @param language
	 *            attributo di xml:lang, seguire le regole di i18n
	 * @return riferimento all'oggetto corrente
	 */
	public Any addDocumentation(String explanation, String language) {
		addAnnotation().addDocumentation(explanation, language);
		return this;
	}
}
